<!DOCTYPE html>
<html  lang="zh-CN" >
<head>
  <meta charset="UTF-8">
  <meta name="viewport"
    content="width=device-width, initial-scale=1.0, minimum-scale=1.0">
  <meta http-equiv="X-UA-Compatible" content="ie=edge">
  <meta name="theme-color" content="#fff" id="theme-color">
  <meta name="description" content="深山磨柴斧，一鸣震江湖">
  <link rel="icon" href="/img/ic_head.jpg">
  <title>022-Android动画（2）：属性动画详解</title>
  
  
  <meta property="og:title" content="022-Android动画（2）：属性动画详解">
  
  
  <meta property="og:url" content="http://example.com/2019/08/28/022-Android%E5%8A%A8%E7%94%BB%EF%BC%882%EF%BC%89%EF%BC%9A%E5%B1%9E%E6%80%A7%E5%8A%A8%E7%94%BB%E8%AF%A6%E8%A7%A3/index.html">
  
  
  <meta property="og:img" content="/img/ic_head.jpg">
  
  
  <meta property="og:img" content="深山磨柴斧，一鸣震江湖">
  
  
  <meta property="og:type" content="article">
  <meta property="og:article:published_time" content="2019-08-28">
  <meta property="og:article:modified_time" content="2021-04-14">
  <meta property="og:article:author" content="Cupster">
  
  
  <meta property="og:article:tag" content="Android">
  
  <meta property="og:article:tag" content="Android动画">
  
  
  
  
  <script>
    // control reverse button
    var reverseDarkList = {
      dark: 'light',
      light: 'dark'
    };
    var themeColor = {
      dark: '#1c1c1e',
      light: '#fff'
    }
    // get the data of css prefers-color-scheme
    var getCssMediaQuery = function() {
      return window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light';
    };
    // reverse current darkmode setting function
    var reverseDarkModeSetting = function() {
      var setting = localStorage.getItem('user-color-scheme');
      if(reverseDarkList[setting]) {
        setting = reverseDarkList[setting];
      } else if(setting === null) {
        setting = reverseDarkList[getCssMediaQuery()];
      } else {
        return;
      }
      localStorage.setItem('user-color-scheme', setting);
      return setting;
    };
    // apply current darkmode setting
    var setDarkmode = function(mode) {
      var setting = mode || localStorage.getItem('user-color-scheme');
      if(setting === getCssMediaQuery()) {
        document.documentElement.removeAttribute('data-user-color-scheme');
        localStorage.removeItem('user-color-scheme');
        document.getElementById('theme-color').content = themeColor[setting];
      } else if(reverseDarkList[setting]) {
        document.documentElement.setAttribute('data-user-color-scheme', setting);
        document.getElementById('theme-color').content = themeColor[setting];
      } else {
        document.documentElement.removeAttribute('data-user-color-scheme');
        localStorage.removeItem('user-color-scheme');
        document.getElementById('theme-color').content = themeColor[getCssMediaQuery()];
      }
    };
    setDarkmode();
  </script>
  <script>
    function loadScript(url, cb) {
      var script = document.createElement('script');
      script.src = url;
      if (cb) script.onload = cb;
      script.async = true;
      document.body.appendChild(script);
    }
  </script>
  
  <link rel="preload" href="//at.alicdn.com/t/font_1946621_i1kgafibvw.css" as="style" >
  <link rel="preload" href="//at.alicdn.com/t/font_1952792_89b4ac4k4up.css" as="style" >
  
  <link rel="preload" href="/js/lib/lightbox/baguetteBox.min.js" as="script">
  <link rel="preload" href="/js/lib/lightbox/baguetteBox.min.css" as="style" >
  
  
  <link rel="preload" href="/js/lib/lozad.min.js" as="script">
  
  
  
  
  
  
  
  
<link rel="stylesheet" href="/css/main.css">

  
  
<link rel="stylesheet" href="//at.alicdn.com/t/font_1946621_i1kgafibvw.css">

  
  
<link rel="stylesheet" href="//at.alicdn.com/t/font_1952792_89b4ac4k4up.css">

  
  
<link rel="stylesheet" href="/js/lib/lightbox/baguetteBox.min.css">

  
  
  
  
<meta name="generator" content="Hexo 5.4.0"></head>


<body>
  <div class="wrapper">
    
    <nav class="navbar">
  <div class="navbar-logo">
    <span class="navbar-logo-main">
      
      <img class="navbar-logo-img" src="/img/ic_head.jpg" alt="logo">
      
      <span class="navbar-logo-dsc">不负明天</span>
    </span>
  </div>
  <div class="navbar-menu">
    
    <a href="/" class="navbar-menu-item">
    
    首页
    
    </a>
    
    <a href="/archives" class="navbar-menu-item">
    
    归档
    
    </a>
    
    <a href="/tags" class="navbar-menu-item">
    
    标签
    
    </a>
    
    <a href="/categories" class="navbar-menu-item">
    
    分类
    
    </a>
    
    <a href="/about" class="navbar-menu-item">
    
    关于
    
    </a>
    
    <a href="/links" class="navbar-menu-item">
    
    友链
    
    </a>
    
    <a class="navbar-menu-item darknavbar" id="dark"><i class="iconfont icon-weather"></i></a>
    <a class="navbar-menu-item searchnavbar" id="search"><i class="iconfont icon-search" style="font-size: 1.2rem; font-weight: 400;"></i></a>
  </div>
</nav>
    
    <div id="local-search" style="display: none;">
      <input class="navbar-menu-item" id="search-input" placeholder="请输入搜索内容...">
      <div id="search-content"></div>
    </div>
    
    <div class="section-wrap">
      <div class="container">
        <div class="columns">
          <main class="main-column">
<article class="card card-content">
  <header>
    <h1 class="post-title">
      022-Android动画（2）：属性动画详解
    </h1>
  </header>
  <div class="post-meta post-show-meta">
    <time datetime="2019-08-28T04:02:35.000Z">
      <i class="iconfont icon-calendar" style="margin-right: 2px;"></i>
      <span>2019-08-28</span>
    </time>
    
    <span class="dot"></span>
    
    <a href="/categories/Android/" class="post-meta-link">Android</a>
    
    
    
    <span class="dot"></span>
    <span>1.5k 字</span>
    
  </div>
  
  <div class="post-meta post-show-meta" style="margin-top: -10px;">
    <div style="display: flex; align-items: center;">
      <i class="iconfont icon-biaoqian" style="margin-right: 2px; font-size: 1.15rem;"></i>
      
      
        <a href="/tags/Android/" class="post-meta-link">Android</a>
      
      
      <span class="dot"></span>
      
        <a href="/tags/Android动画/" class="post-meta-link">Android动画</a>
      
    </div>
  </div>
  
  </header>
  <div id="section" class="post-content">
    <p><a target="_blank" rel="noopener" href="https://blog.csdn.net/Cupster/article/details/113616486">【5年Android从零复盘系列之二十二】Android动画（2）：属性动画</a></p>
<hr/>


<h1 id="1-简述"><a href="#1-简述" class="headerlink" title="1.简述"></a>1.简述</h1><p>Android有三种动画，分别是<a target="_blank" rel="noopener" href="https://blog.csdn.net/Cupster/article/details/113524191">视图动画</a>，属性动画，帧动画。</p>
<p>其中，帧动画因为资源占用大、性能差、内存溢出等不足,已被废弃。</p>
<p>属性动画是Android最常用的动画方案，具有以下优势：</p>
<ol>
<li>动画效果包括但不限于平移、旋转、缩放、透明；</li>
<li>作用对象包括但不限于View;</li>
<li>同等条件下，属性动画性能&amp;资源占用优于视图动画；</li>
<li>高可定制化</li>
</ol>
<h1 id="2-原理"><a href="#2-原理" class="headerlink" title="2. 原理"></a>2. 原理</h1><p>ValueAnimator类是通过不断控制 值 的变化，再实时赋给对象，从而实现动画效果</p>
<p>ObjectAnimator类直接改变对象的属性值，从而实现动画效果</p>
<h1 id="3-ValueAnimator使用"><a href="#3-ValueAnimator使用" class="headerlink" title="3. ValueAnimator使用"></a>3. ValueAnimator使用</h1><p>ValueAnimator有三个动画构造器方法：（int values）、ofFloat（float values）、ofObject（int values）</p>
<p>三个方法的区别可以理解为只是使用的估值器不一样，原理都是值的改变过程。</p>
<p>属性动画建议以Java动态代码的方式获取动画对象，方便灵活设定值；</p>
<h1 id="3-1-ofFloat"><a href="#3-1-ofFloat" class="headerlink" title="3.1 ofFloat"></a>3.1 ofFloat</h1><p>使用浮点型估值器FloatEvaluator ，以float类型的数值，将初始值变化到结束值</p>
<pre class="highlight"><span class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">static</span> Animator <span class="title">startValueAnim</span><span class="params">(<span class="keyword">float</span>... changeArr ,)</span></span>&#123;</span><br><span class="line"><span class="comment">//        ValueAnimator anim = ValueAnimator.ofFloat(0f, 1f);//从0平滑过渡到1</span></span><br><span class="line">        ValueAnimator anim = ValueAnimator.ofFloat(changeArr);<span class="comment">//传入几个就是连续过渡到每个值，直至最后一个值，如0，1，0.8，1</span></span><br><span class="line">        anim.setDuration(<span class="number">300</span>);</span><br><span class="line">        anim.addUpdateListener(<span class="keyword">new</span> ValueAnimator.AnimatorUpdateListener() &#123;</span><br><span class="line">            <span class="meta">@Override</span></span><br><span class="line">            <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">onAnimationUpdate</span><span class="params">(ValueAnimator valueAnimator)</span> </span>&#123;</span><br><span class="line"></span><br><span class="line">            &#125;</span><br><span class="line">        &#125;);</span><br><span class="line">        <span class="keyword">return</span> anim;</span><br><span class="line">    &#125;</span><br></pre>

<h2 id="3-2-ofInt"><a href="#3-2-ofInt" class="headerlink" title="3.2 ofInt"></a>3.2 ofInt</h2><p>与ofFloat使用方式一致，ofInt是使用整型估值器IntEvaluator ，以int类型的数值，将初始值变化到结束值</p>
<pre class="highlight"><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> Animator <span class="title">startValueAnim</span><span class="params">(<span class="keyword">int</span>... changeArr ,)</span></span>&#123;</span><br><span class="line"><span class="comment">//        ValueAnimator anim = ValueAnimator.ofFloat(0, 100);//从0平滑过渡到100</span></span><br><span class="line">        ValueAnimator anim = ValueAnimator.ofInt(changeArr);<span class="comment">//传入几个就是连续过渡到每个值，直至最后一个值，如0，100，20，100</span></span><br><span class="line">        anim.setDuration(<span class="number">300</span>);</span><br><span class="line">        anim.addUpdateListener(<span class="keyword">new</span> ValueAnimator.AnimatorUpdateListener() &#123;</span><br><span class="line">            <span class="meta">@Override</span></span><br><span class="line">            <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">onAnimationUpdate</span><span class="params">(ValueAnimator valueAnimator)</span> </span>&#123;</span><br><span class="line"></span><br><span class="line">            &#125;</span><br><span class="line">        &#125;);</span><br><span class="line">        <span class="keyword">return</span> anim;</span><br><span class="line">    &#125;</span><br></pre>

<h2 id="3-3-ofObject"><a href="#3-3-ofObject" class="headerlink" title="3.3 ofObject"></a>3.3 ofObject</h2><p>ofObject可以说是ValueAnimator的核心成员，用法与上述一致，需自定义进度值变化，即编写实现TypeEvaluator类：</p>
<pre class="highlight"><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">FloatOutEvaluator</span> <span class="keyword">implements</span> <span class="title">TypeEvaluator</span> </span>&#123;</span><br><span class="line">    <span class="comment">/**</span></span><br><span class="line"><span class="comment">     *</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@param</span> fraction 进度值</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@param</span> startValue 起始值</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@param</span> endValue 终点值</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@return</span></span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line">    <span class="meta">@Override</span></span><br><span class="line">    <span class="function"><span class="keyword">public</span> Object <span class="title">evaluate</span><span class="params">(<span class="keyword">float</span> fraction, Object startValue, Object endValue)</span> </span>&#123;</span><br><span class="line">        <span class="keyword">float</span> startFloat = ((Number) startValue).floatValue();</span><br><span class="line">        <span class="keyword">float</span> cf = fraction;</span><br><span class="line">        <span class="keyword">if</span> (fraction&lt;<span class="number">0.3f</span>)&#123;</span><br><span class="line">            cf = fraction*<span class="number">2</span>;<span class="comment">//前30%进度-进度加倍</span></span><br><span class="line">        &#125;<span class="keyword">else</span> <span class="keyword">if</span> (fraction &lt;<span class="number">0.6f</span>)&#123;</span><br><span class="line">            cf = <span class="number">0.6f</span>;<span class="comment">//暂停一会</span></span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">return</span> startFloat +  cf* (((Number) endValue).floatValue() - startFloat);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre>

<p>使用</p>
<pre class="highlight"><span class="line">ValueAnimator animator = ValueAnimator.ofObject(<span class="keyword">new</span> FloatOutEvaluator() , <span class="number">0f</span>,<span class="number">1f</span>);</span><br><span class="line">animator.setDuration(<span class="number">3000</span>);</span><br><span class="line">animator.addUpdateListener(<span class="keyword">new</span> ValueAnimator.AnimatorUpdateListener() &#123;</span><br><span class="line">    <span class="meta">@Override</span></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">onAnimationUpdate</span><span class="params">(ValueAnimator valueAnimator)</span> </span>&#123;</span><br><span class="line">        <span class="comment">//使用变化值，赋值，刷新，产生动画</span></span><br><span class="line">        view.setAlpha((Float) valueAnimator.getAnimatedValue());</span><br><span class="line">    &#125;</span><br><span class="line">&#125;);</span><br></pre>

<h1 id="4-ObjectAnimator"><a href="#4-ObjectAnimator" class="headerlink" title="4. ObjectAnimator"></a>4. ObjectAnimator</h1><p>ObjectAnimator 是Android开发实际使用最多的动画，可以直接创建的几种动画及组合动画</p>
<h2 id="4-1-Java代码方式"><a href="#4-1-Java代码方式" class="headerlink" title="4.1 Java代码方式"></a>4.1 Java代码方式</h2><p>动画：透明渐变两次</p>
<pre class="highlight"><span class="line">ObjectAnimator animator = ObjectAnimator.ofFloat(view, <span class="string">&quot;alpha&quot;</span>, <span class="number">1f</span>, <span class="number">0f</span>, <span class="number">1f</span>,<span class="number">0f</span>);</span><br><span class="line">animator.setDuration(<span class="number">3000</span>);</span><br><span class="line">animator.start();</span><br></pre>

<p>同理有：</p>
<ol>
<li>旋转rotation</li>
<li>平移translationX、translationY</li>
<li>缩放scaleX、scaleY</li>
<li>透明变化alpha</li>
</ol>
<h2 id="4-2-xml方式"><a href="#4-2-xml方式" class="headerlink" title="4.2 xml方式"></a>4.2 xml方式</h2><p>属性动画xml资源文件的目录是 res/animator ,与视图动画的资源目录 res/anim不是同一个</p>
<p>举例</p>
<pre class="highlight"><span class="line"><span class="tag">&lt;<span class="name">objectAnimator</span> <span class="attr">xmlns:android</span>=<span class="string">&quot;http://schemas.android.com/apk/res/android&quot;</span></span></span><br><span class="line"><span class="tag">    <span class="attr">android:valueFrom</span>=<span class="string">&quot;0&quot;</span></span></span><br><span class="line"><span class="tag">    <span class="attr">android:valueTo</span>=<span class="string">&quot;1.0&quot;</span></span></span><br><span class="line"><span class="tag">    <span class="attr">android:valueType</span>=<span class="string">&quot;floatType&quot;</span></span></span><br><span class="line"><span class="tag">    <span class="attr">android:propertyName</span>=<span class="string">&quot;alpha&quot;</span>/&gt;</span></span><br></pre>
<p>加载使用动画</p>
<pre class="highlight"><span class="line">Animator animator = AnimatorInflater.loadAnimator(context, R.animator.anim_alpha);</span><br><span class="line">animator.setTarget(view);</span><br><span class="line">animator.start();</span><br></pre>

<p>同理其他动画rotateion、scale、translate..</p>
<h2 id="4-3-ObjectAnimator扩展-amp-自定义TypeEvaluator估值器"><a href="#4-3-ObjectAnimator扩展-amp-自定义TypeEvaluator估值器" class="headerlink" title="4.3 ObjectAnimator扩展 &amp; 自定义TypeEvaluator估值器"></a>4.3 ObjectAnimator扩展 &amp; 自定义TypeEvaluator估值器</h2><p>扩展“color”动画</p>
<img src="https:/ srcset="data:image/svg+xml,%3Csvg%20xmlns='http://www.w3.org/2000/svg'%20viewBox='0%200%20300%20300'%3E%3C/svg%3E" data-src="https://gitee.com/cupster/picbed/raw/master/uPic/20210203165433_color.gif" class="lozad post-image"/gitee.com/cupster/picbed/raw/master/uPic/20210203165433_color.gif"/>


<p>1.定义一个View，包含setColor()方法</p>
<pre class="highlight"><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">ColorTextView</span> <span class="keyword">extends</span> <span class="title">TextView</span> </span>&#123;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">setColor</span><span class="params">(String color)</span></span>&#123;</span><br><span class="line">        setTextColor(Color.parseColor(color));</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="title">ColorTextView</span><span class="params">(Context context)</span> </span>&#123;</span><br><span class="line">        <span class="keyword">super</span>(context);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="title">ColorTextView</span><span class="params">(Context context, <span class="meta">@Nullable</span> AttributeSet attrs)</span> </span>&#123;</span><br><span class="line">        <span class="keyword">super</span>(context, attrs);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre>

<p>2.布局使用</p>
<pre class="highlight"><span class="line"><span class="meta">&lt;?xml version=&quot;1.0&quot; encoding=&quot;utf-8&quot;?&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">androidx.constraintlayout.widget.ConstraintLayout</span> <span class="attr">xmlns:android</span>=<span class="string">&quot;http://schemas.android.com/apk/res/android&quot;</span></span></span><br><span class="line"><span class="tag">    <span class="attr">xmlns:app</span>=<span class="string">&quot;http://schemas.android.com/apk/res-auto&quot;</span></span></span><br><span class="line"><span class="tag">    <span class="attr">xmlns:tools</span>=<span class="string">&quot;http://schemas.android.com/tools&quot;</span></span></span><br><span class="line"><span class="tag">    <span class="attr">android:layout_width</span>=<span class="string">&quot;match_parent&quot;</span></span></span><br><span class="line"><span class="tag">    <span class="attr">android:layout_height</span>=<span class="string">&quot;match_parent&quot;</span></span></span><br><span class="line"><span class="tag">    <span class="attr">tools:context</span>=<span class="string">&quot;.MainActivity&quot;</span>&gt;</span></span><br><span class="line">    &lt;com.cupster.animation.ColorTextView</span><br><span class="line">        android:id=&quot;@+id/anim_view&quot;</span><br><span class="line">        android:layout_width=&quot;wrap_content&quot;</span><br><span class="line">        android:layout_height=&quot;wrap_content&quot;</span><br><span class="line">        android:text=&quot;测试颜色动画的文字&quot;</span><br><span class="line">        app:layout_constraintBottom_toBottomOf=&quot;parent&quot;</span><br><span class="line">        app:layout_constraintLeft_toLeftOf=&quot;parent&quot;</span><br><span class="line">        app:layout_constraintRight_toRightOf=&quot;parent&quot;</span><br><span class="line">        app:layout_constraintTop_toTopOf=&quot;parent&quot; /&gt;</span><br><span class="line"><span class="tag">&lt;/<span class="name">androidx.constraintlayout.widget.ConstraintLayout</span>&gt;</span></span><br></pre>

<p>3.编写估值器ColorEvaluator，控制颜色随着进度值改变而改变的规则</p>
<pre class="highlight"><span class="line"><span class="keyword">package</span> com.cupster.animation;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> android.animation.TypeEvaluator;</span><br><span class="line"></span><br><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * 此处代码为郭霖大神编写的自定义Evaluator，用于扩展属性动画:&quot;color&quot;,</span></span><br><span class="line"><span class="comment"> * 使用该动画的View需设置对应public void setColor,并在其中调用invalidate()</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">ColorEvaluator</span> <span class="keyword">implements</span> <span class="title">TypeEvaluator</span> </span>&#123;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">private</span> <span class="keyword">int</span> mCurrentRed = -<span class="number">1</span>;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">private</span> <span class="keyword">int</span> mCurrentGreen = -<span class="number">1</span>;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">private</span> <span class="keyword">int</span> mCurrentBlue = -<span class="number">1</span>;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@Override</span></span><br><span class="line">    <span class="function"><span class="keyword">public</span> Object <span class="title">evaluate</span><span class="params">(<span class="keyword">float</span> fraction, Object startValue, Object endValue)</span> </span>&#123;</span><br><span class="line">        String startColor = (String) startValue;</span><br><span class="line">        String endColor = (String) endValue;</span><br><span class="line">        <span class="keyword">int</span> startRed = Integer.parseInt(startColor.substring(<span class="number">1</span>, <span class="number">3</span>), <span class="number">16</span>);</span><br><span class="line">        <span class="keyword">int</span> startGreen = Integer.parseInt(startColor.substring(<span class="number">3</span>, <span class="number">5</span>), <span class="number">16</span>);</span><br><span class="line">        <span class="keyword">int</span> startBlue = Integer.parseInt(startColor.substring(<span class="number">5</span>, <span class="number">7</span>), <span class="number">16</span>);</span><br><span class="line">        <span class="keyword">int</span> endRed = Integer.parseInt(endColor.substring(<span class="number">1</span>, <span class="number">3</span>), <span class="number">16</span>);</span><br><span class="line">        <span class="keyword">int</span> endGreen = Integer.parseInt(endColor.substring(<span class="number">3</span>, <span class="number">5</span>), <span class="number">16</span>);</span><br><span class="line">        <span class="keyword">int</span> endBlue = Integer.parseInt(endColor.substring(<span class="number">5</span>, <span class="number">7</span>), <span class="number">16</span>);</span><br><span class="line">        <span class="comment">// 初始化颜色的值</span></span><br><span class="line">        <span class="keyword">if</span> (mCurrentRed == -<span class="number">1</span>) &#123;</span><br><span class="line">            mCurrentRed = startRed;</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">if</span> (mCurrentGreen == -<span class="number">1</span>) &#123;</span><br><span class="line">            mCurrentGreen = startGreen;</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">if</span> (mCurrentBlue == -<span class="number">1</span>) &#123;</span><br><span class="line">            mCurrentBlue = startBlue;</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="comment">// 计算初始颜色和结束颜色之间的差值</span></span><br><span class="line">        <span class="keyword">int</span> redDiff = Math.abs(startRed - endRed);</span><br><span class="line">        <span class="keyword">int</span> greenDiff = Math.abs(startGreen - endGreen);</span><br><span class="line">        <span class="keyword">int</span> blueDiff = Math.abs(startBlue - endBlue);</span><br><span class="line">        <span class="keyword">int</span> colorDiff = redDiff + greenDiff + blueDiff;</span><br><span class="line">        <span class="keyword">if</span> (mCurrentRed != endRed) &#123;</span><br><span class="line">            mCurrentRed = getCurrentColor(startRed, endRed, colorDiff, <span class="number">0</span>,</span><br><span class="line">                    fraction);</span><br><span class="line">        &#125; <span class="keyword">else</span> <span class="keyword">if</span> (mCurrentGreen != endGreen) &#123;</span><br><span class="line">            mCurrentGreen = getCurrentColor(startGreen, endGreen, colorDiff,</span><br><span class="line">                    redDiff, fraction);</span><br><span class="line">        &#125; <span class="keyword">else</span> <span class="keyword">if</span> (mCurrentBlue != endBlue) &#123;</span><br><span class="line">            mCurrentBlue = getCurrentColor(startBlue, endBlue, colorDiff,</span><br><span class="line">                    redDiff + greenDiff, fraction);</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="comment">// 将计算出的当前颜色的值组装返回</span></span><br><span class="line">        String currentColor = <span class="string">&quot;#&quot;</span> + getHexString(mCurrentRed)</span><br><span class="line">                + getHexString(mCurrentGreen) + getHexString(mCurrentBlue);</span><br><span class="line">        <span class="keyword">return</span> currentColor;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="comment">/**</span></span><br><span class="line"><span class="comment">     * 根据fraction值来计算当前的颜色。</span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line">    <span class="function"><span class="keyword">private</span> <span class="keyword">int</span> <span class="title">getCurrentColor</span><span class="params">(<span class="keyword">int</span> startColor, <span class="keyword">int</span> endColor, <span class="keyword">int</span> colorDiff,</span></span></span><br><span class="line"><span class="function"><span class="params">                                <span class="keyword">int</span> offset, <span class="keyword">float</span> fraction)</span> </span>&#123;</span><br><span class="line">        <span class="keyword">int</span> currentColor;</span><br><span class="line">        <span class="keyword">if</span> (startColor &gt; endColor) &#123;</span><br><span class="line">            currentColor = (<span class="keyword">int</span>) (startColor - (fraction * colorDiff - offset));</span><br><span class="line">            <span class="keyword">if</span> (currentColor &lt; endColor) &#123;</span><br><span class="line">                currentColor = endColor;</span><br><span class="line">            &#125;</span><br><span class="line">        &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">            currentColor = (<span class="keyword">int</span>) (startColor + (fraction * colorDiff - offset));</span><br><span class="line">            <span class="keyword">if</span> (currentColor &gt; endColor) &#123;</span><br><span class="line">                currentColor = endColor;</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">return</span> currentColor;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="comment">/**</span></span><br><span class="line"><span class="comment">     * 将10进制颜色值转换成16进制。</span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line">    <span class="function"><span class="keyword">private</span> String <span class="title">getHexString</span><span class="params">(<span class="keyword">int</span> value)</span> </span>&#123;</span><br><span class="line">        String hexString = Integer.toHexString(value);</span><br><span class="line">        <span class="keyword">if</span> (hexString.length() == <span class="number">1</span>) &#123;</span><br><span class="line">            hexString = <span class="string">&quot;0&quot;</span> + hexString;</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">return</span> hexString;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">&#125;</span><br><span class="line"></span><br></pre>
<p>4.封装通用方法</p>
<pre class="highlight"><span class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">propColorAnimator</span><span class="params">(ColorTextView target , String startColor , String endColor)</span></span>&#123;</span><br><span class="line">        ObjectAnimator animator = ObjectAnimator.ofObject(target ,<span class="string">&quot;color&quot;</span>,<span class="keyword">new</span> ColorEvaluator() ,startColor,endColor);</span><br><span class="line">        animator.setDuration(<span class="number">3000</span>);</span><br><span class="line">        animator.start();</span><br><span class="line">    &#125;</span><br></pre>

<p>5.使用</p>
<pre class="highlight"><span class="line"></span><br><span class="line">tv = findViewById(R.id.anim_view);</span><br><span class="line">tv.setOnClickListener(<span class="keyword">new</span> View.OnClickListener() &#123;</span><br><span class="line">    <span class="meta">@Override</span></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">onClick</span><span class="params">(View view)</span> </span>&#123;</span><br><span class="line">        PropAnimatorHelper.propColorAnimator((ColorTextView) view,<span class="string">&quot;#a7dbf7&quot;</span> ,<span class="string">&quot;#ff8696&quot;</span>);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;);</span><br></pre>





  </div>
  <div>
  
  <div class="post-note note-warning copyright" style="margin-top: 42px">
    <p><span style="font-weight: bold;">作者：</span><a target="_blank" rel="nofollow noopener noreferrer" href="http://example.com/about">Cupster</a></p>
    <p><span style="font-weight: bold;">文章链接：</span><a target="_blank" rel="nofollow noopener noreferrer" href="http://example.com/2019/08/28/022-Android%E5%8A%A8%E7%94%BB%EF%BC%882%EF%BC%89%EF%BC%9A%E5%B1%9E%E6%80%A7%E5%8A%A8%E7%94%BB%E8%AF%A6%E8%A7%A3/">http://example.com/2019/08/28/022-Android%E5%8A%A8%E7%94%BB%EF%BC%882%EF%BC%89%EF%BC%9A%E5%B1%9E%E6%80%A7%E5%8A%A8%E7%94%BB%E8%AF%A6%E8%A7%A3/</a></p>
    <p><span style="font-weight: bold;">版权声明：</span>本博客所有文章除特别声明外，均采用<a target="_blank" rel="noopener" href="https://creativecommons.org/licenses/by-nc-sa/4.0/deed.zh">CC BY-NC-SA 4.0 协议</a>。转载请注明出处！</p>
  </div>
  
  </div>
</article>
<div class="nav">
  
  <div class="nav-item-prev">
    <a href="/2019/09/02/023-Android动画（3）：插值器与估值器详解/" class="nav-link">
      <i class="iconfont icon-left nav-prev-icon"></i>
      <div>
        <div class="nav-label">上一篇</div>
        
        <div class="nav-title">023-Android动画（3）：插值器与估值器详解 </div>
        
      </div>
    </a>
  </div>
  
  
  <div class="nav-item-next">
    <a href="/2019/08/22/021-Android动画（1）：视图动画详解(图文)/" class="nav-link">
      <div>
        <div class="nav-label">下一篇</div>
        
        <div class="nav-title">021-Android动画（1）：视图动画详解(图文) </div>
        
      </div>
      <i class="iconfont icon-right nav-next-icon"></i>
    </a>
  </div>
  
</div>

<div class="card card-content toc-card" id="mobiletoc">
  <div class="toc-header"><i class="iconfont icon-menu" style="padding-right: 2px;"></i>目录</div>
<ol class="toc"><li class="toc-item toc-level-1"><a class="toc-link" href="#1-%E7%AE%80%E8%BF%B0"><span class="toc-text">1.简述</span></a></li><li class="toc-item toc-level-1"><a class="toc-link" href="#2-%E5%8E%9F%E7%90%86"><span class="toc-text">2. 原理</span></a></li><li class="toc-item toc-level-1"><a class="toc-link" href="#3-ValueAnimator%E4%BD%BF%E7%94%A8"><span class="toc-text">3. ValueAnimator使用</span></a></li><li class="toc-item toc-level-1"><a class="toc-link" href="#3-1-ofFloat"><span class="toc-text">3.1 ofFloat</span></a><ol class="toc-child"><li class="toc-item toc-level-2"><a class="toc-link" href="#3-2-ofInt"><span class="toc-text">3.2 ofInt</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#3-3-ofObject"><span class="toc-text">3.3 ofObject</span></a></li></ol></li><li class="toc-item toc-level-1"><a class="toc-link" href="#4-ObjectAnimator"><span class="toc-text">4. ObjectAnimator</span></a><ol class="toc-child"><li class="toc-item toc-level-2"><a class="toc-link" href="#4-1-Java%E4%BB%A3%E7%A0%81%E6%96%B9%E5%BC%8F"><span class="toc-text">4.1 Java代码方式</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#4-2-xml%E6%96%B9%E5%BC%8F"><span class="toc-text">4.2 xml方式</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#4-3-ObjectAnimator%E6%89%A9%E5%B1%95-amp-%E8%87%AA%E5%AE%9A%E4%B9%89TypeEvaluator%E4%BC%B0%E5%80%BC%E5%99%A8"><span class="toc-text">4.3 ObjectAnimator扩展 &amp; 自定义TypeEvaluator估值器</span></a></li></ol></li></ol>
</div></main>
          <aside class="left-column">
            
            <div class="card card-author">
              
<img src="/img/ic_head.jpg" class="author-img">

<p class="author-name">Cupster</p>
<p class="author-description">深山磨柴斧，一鸣震江湖</p>
<div class="author-message">
  <a class="author-posts-count" href="/archives">
    <span>66</span>
    <span>文章</span>
  </a>
  <a class="author-categories-count" href="/categories">
    <span>5</span>
    <span>分类</span>
  </a>
  <a class="author-tags-count" href="/tags">
    <span>31</span>
    <span>标签</span>
  </a>
</div>

<div class="author-card-society">
  
    <div class="author-card-society-icon">
      <a target="_blank" rel="noopener" href="https://cupster.blog.csdn.net/">
        <i class="iconfont /img/ic_csdn.png society-icon"></i>
      </a>
    </div>
  
</div>

            </div>
            
            <div class="sticky-tablet">
  
  
  <article class="display-when-two-columns spacer">
    <div class="card card-content toc-card">
      <div class="toc-header"><i class="iconfont icon-menu" style="padding-right: 2px;"></i>目录</div>
<ol class="toc"><li class="toc-item toc-level-1"><a class="toc-link" href="#1-%E7%AE%80%E8%BF%B0"><span class="toc-text">1.简述</span></a></li><li class="toc-item toc-level-1"><a class="toc-link" href="#2-%E5%8E%9F%E7%90%86"><span class="toc-text">2. 原理</span></a></li><li class="toc-item toc-level-1"><a class="toc-link" href="#3-ValueAnimator%E4%BD%BF%E7%94%A8"><span class="toc-text">3. ValueAnimator使用</span></a></li><li class="toc-item toc-level-1"><a class="toc-link" href="#3-1-ofFloat"><span class="toc-text">3.1 ofFloat</span></a><ol class="toc-child"><li class="toc-item toc-level-2"><a class="toc-link" href="#3-2-ofInt"><span class="toc-text">3.2 ofInt</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#3-3-ofObject"><span class="toc-text">3.3 ofObject</span></a></li></ol></li><li class="toc-item toc-level-1"><a class="toc-link" href="#4-ObjectAnimator"><span class="toc-text">4. ObjectAnimator</span></a><ol class="toc-child"><li class="toc-item toc-level-2"><a class="toc-link" href="#4-1-Java%E4%BB%A3%E7%A0%81%E6%96%B9%E5%BC%8F"><span class="toc-text">4.1 Java代码方式</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#4-2-xml%E6%96%B9%E5%BC%8F"><span class="toc-text">4.2 xml方式</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#4-3-ObjectAnimator%E6%89%A9%E5%B1%95-amp-%E8%87%AA%E5%AE%9A%E4%B9%89TypeEvaluator%E4%BC%B0%E5%80%BC%E5%99%A8"><span class="toc-text">4.3 ObjectAnimator扩展 &amp; 自定义TypeEvaluator估值器</span></a></li></ol></li></ol>
    </div>
  </article>
  
  
  <article class="card card-content categories-widget">
    <div class="categories-card">
  <div class="categories-header"><i class="iconfont icon-fenlei" style="padding-right: 2px;"></i>分类</div>
  <div class="categories-list">
    
      <a href="/categories/Android/">
        <div class="categories-list-item">
          Android
          <span class="categories-list-item-badge">38</span>
        </div>
      </a>
    
      <a href="/categories/Linux/">
        <div class="categories-list-item">
          Linux
          <span class="categories-list-item-badge">6</span>
        </div>
      </a>
    
      <a href="/categories/Dev-Base/">
        <div class="categories-list-item">
          Dev-Base
          <span class="categories-list-item-badge">12</span>
        </div>
      </a>
    
      <a href="/categories/Kotlin/">
        <div class="categories-list-item">
          Kotlin
          <span class="categories-list-item-badge">9</span>
        </div>
      </a>
    
      <a href="/categories/自动化脚本/">
        <div class="categories-list-item">
          自动化脚本
          <span class="categories-list-item-badge">1</span>
        </div>
      </a>
    
  </div>
</div>
  </article>
  
  <article class="card card-content tags-widget">
    <div class="tags-card">
  <div class="tags-header"><i class="iconfont icon-biaoqian" style="padding-right: 2px;"></i>热门标签</div>
  <div class="tags-list">
    
    <a href="/tags/Android/" title="Android"><div class="tags-list-item">Android</div></a>
    
    <a href="/tags/Android自定义View/" title="Android自定义View"><div class="tags-list-item">Android自定义View</div></a>
    
    <a href="/tags/MacOS/" title="MacOS"><div class="tags-list-item">MacOS</div></a>
    
    <a href="/tags/Kotlin/" title="Kotlin"><div class="tags-list-item">Kotlin</div></a>
    
    <a href="/tags/Android持久化/" title="Android持久化"><div class="tags-list-item">Android持久化</div></a>
    
    <a href="/tags/CentOS/" title="CentOS"><div class="tags-list-item">CentOS</div></a>
    
    <a href="/tags/Linux/" title="Linux"><div class="tags-list-item">Linux</div></a>
    
    <a href="/tags/Android事件/" title="Android事件"><div class="tags-list-item">Android事件</div></a>
    
    <a href="/tags/Android基础/" title="Android基础"><div class="tags-list-item">Android基础</div></a>
    
    <a href="/tags/Android手势/" title="Android手势"><div class="tags-list-item">Android手势</div></a>
    
    <a href="/tags/Scrcpy/" title="Scrcpy"><div class="tags-list-item">Scrcpy</div></a>
    
    <a href="/tags/Android动画/" title="Android动画"><div class="tags-list-item">Android动画</div></a>
    
    <a href="/tags/Git/" title="Git"><div class="tags-list-item">Git</div></a>
    
    <a href="/tags/Java/" title="Java"><div class="tags-list-item">Java</div></a>
    
    <a href="/tags/Docker/" title="Docker"><div class="tags-list-item">Docker</div></a>
    
    <a href="/tags/Android-Dialog/" title="Android Dialog"><div class="tags-list-item">Android Dialog</div></a>
    
  </div>
</div>
  </article>
  
  
</div>
          </aside>
          <aside class="right-column">
            <div class="sticky-widescreen">
  
  
  <article class="card card-content toc-card">
    <div class="toc-header"><i class="iconfont icon-menu" style="padding-right: 2px;"></i>目录</div>
<ol class="toc"><li class="toc-item toc-level-1"><a class="toc-link" href="#1-%E7%AE%80%E8%BF%B0"><span class="toc-text">1.简述</span></a></li><li class="toc-item toc-level-1"><a class="toc-link" href="#2-%E5%8E%9F%E7%90%86"><span class="toc-text">2. 原理</span></a></li><li class="toc-item toc-level-1"><a class="toc-link" href="#3-ValueAnimator%E4%BD%BF%E7%94%A8"><span class="toc-text">3. ValueAnimator使用</span></a></li><li class="toc-item toc-level-1"><a class="toc-link" href="#3-1-ofFloat"><span class="toc-text">3.1 ofFloat</span></a><ol class="toc-child"><li class="toc-item toc-level-2"><a class="toc-link" href="#3-2-ofInt"><span class="toc-text">3.2 ofInt</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#3-3-ofObject"><span class="toc-text">3.3 ofObject</span></a></li></ol></li><li class="toc-item toc-level-1"><a class="toc-link" href="#4-ObjectAnimator"><span class="toc-text">4. ObjectAnimator</span></a><ol class="toc-child"><li class="toc-item toc-level-2"><a class="toc-link" href="#4-1-Java%E4%BB%A3%E7%A0%81%E6%96%B9%E5%BC%8F"><span class="toc-text">4.1 Java代码方式</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#4-2-xml%E6%96%B9%E5%BC%8F"><span class="toc-text">4.2 xml方式</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#4-3-ObjectAnimator%E6%89%A9%E5%B1%95-amp-%E8%87%AA%E5%AE%9A%E4%B9%89TypeEvaluator%E4%BC%B0%E5%80%BC%E5%99%A8"><span class="toc-text">4.3 ObjectAnimator扩展 &amp; 自定义TypeEvaluator估值器</span></a></li></ol></li></ol>
  </article>
  
  
  <article class="card card-content">
    <div class="recent-posts-card">
  <div class="recent-posts-header"><i class="iconfont icon-wenzhang_huaban" style="padding-right: 2px;"></i>最近文章</div>
  <div class="recent-posts-list">
    
      <div class="recent-posts-item">
        <div class="recent-posts-item-title">2021-03-02</div>
        <a href="/2021/03/02/Git commit规范/"><div class="recent-posts-item-content">Git commit规范</div></a>
      </div>
    
      <div class="recent-posts-item">
        <div class="recent-posts-item-title">2021-02-16</div>
        <a href="/2021/02/16/AutoJS一文精通AutoJS脚本教程详解/"><div class="recent-posts-item-content">AutoJS一文精通AutoJS脚本教程详解</div></a>
      </div>
    
      <div class="recent-posts-item">
        <div class="recent-posts-item-title">2021-01-21</div>
        <a href="/2021/01/21/架构师进阶：注解Annotation全解/"><div class="recent-posts-item-content">架构师进阶：注解Annotation全解</div></a>
      </div>
    
      <div class="recent-posts-item">
        <div class="recent-posts-item-title">2021-01-06</div>
        <a href="/2021/01/06/ConstraintLayout详解/"><div class="recent-posts-item-content">ConstraintLayout详解</div></a>
      </div>
    
  </div>
</div>
  </article>
  
  
</div>
          </aside>
        </div>
      </div>
    </div>
  </div>
  
  <footer class="footer">
  <div class="footer-container">
    <div>
      <div class="footer-dsc">
        <span>Copyright ©
          
          2020 -
          
          2021
        </span>
        &nbsp;
        <a href="/" class="footer-link">不负明天 </a>
      </div>
    </div>

    
    <div class="footer-dsc">
      
      Powered by
      <a href="https://hexo.io/" class="footer-link" target="_blank" rel="nofollow noopener noreferrer">&nbsp;Hexo </a>
      
      
      <span>&nbsp;|&nbsp;</span>
      
      
      Theme -
      <a href="https://github.com/theme-kaze" class="footer-link" target="_blank"
        rel="nofollow noopener noreferrer">&nbsp;Kaze</a>
      
    </div>
    
    
    
    
      <div class="footer-dsc">
        
        本站总访问量686<span id="busuanzi_value_site_pv"></span>次
        
        
        <span>&nbsp;|&nbsp;</span>
        
        
        本站总访客数219<span id="busuanzi_value_site_uv"></span>次
        
      </div>
      
    
</footer>
  <a role="button" id="scrollbutton" class="basebutton"  aria-label="回到顶部">
  <i class="iconfont icon-arrowleft button-icon"></i>
</a>
<a role="button" id="menubutton" class="basebutton">
  <i class="iconfont icon-menu button-icon"></i>
</a>
<a role="button" id="popbutton" class="basebutton" aria-label="控制中心">
  <i class="iconfont icon-expand button-icon"></i>
</a>
<a role="button" id="darkbutton" class="basebutton darkwidget" aria-label="夜色模式">
  <i class="iconfont icon-weather button-icon"></i>
</a>
<a role="button" id="searchbutton" class="basebutton searchwidget" aria-label="搜索">
  <i class="iconfont icon-search button-icon"></i>
</a>

  
  
  
  <script>
  var addImgLayout = function () {
    var img = document.querySelectorAll('.post-content img');
    var i;
    for (i = 0; i < img.length; i++) {
      var wrapper = document.createElement('a');
      wrapper.setAttribute('href', img[i].getAttribute('data-src'));
      wrapper.setAttribute('aria-label', 'illustration');
      wrapper.style.cssText = 'width: 100%; display: flex; justify-content: center;';
      if (img[i].alt) wrapper.dataset.caption = img[i].alt;
      wrapper.dataset.nolink = true;
      img[i].before(wrapper);
      wrapper.append(img[i]);
      var divWrap = document.createElement('div');
      divWrap.classList.add('gallery');
      wrapper.before(divWrap);
      divWrap.append(wrapper);
    }
    baguetteBox.run('.gallery');
  }
</script>
<script>loadScript("/js/lib/lightbox/baguetteBox.min.js", addImgLayout)</script>
  
  
  
<script src="/js/main.js"></script>

  
  <script>loadScript("/js/lib/busuanzi.min.js")</script>
  
  
  <script>
    var addLazyload = function () {
      var observer = lozad('.lozad', {
        load: function (el) {
          el.srcset = el.getAttribute('data-src');
        },
        loaded: function (el) {
          el.classList.add('loaded');
        }
      });
      observer.observe();
    }
  </script>
  <script>loadScript("/js/lib/lozad.min.js", addLazyload)</script>
  
  
</body>

</html>